Migrar da programação serial em CPU para programação em GPU exige uma mudança de paradigma: da iteração por elementos para execução baseada em blocos. Já não vemos os dados como uma sequência de escalares, mas como coleções de "blocos" agendados para saturar a largura de banda do hardware.
1. Limitado por Memória vs. Limitado por Computação
O gargalo de um kernel é determinado pela razão entre operações matemáticas e acessos à memória. A soma de vetores geralmente é limitada por memória porque realiza apenas uma adição para cada três operações de memória (2 leituras, 1 escrita). O hardware gasta mais tempo esperando pelo DRAM do que calculando.
2. O Papel do BLOCK_SIZE
BLOCK_SIZE define a granularidade da paralelização. Se for muito pequeno, subutilizamos os largos canais de execução da GPU. Um tamanho ótimo garante suficiente "trabalho em andamento" para saturar o barramento de memória.
3. Ocultação de Latência por Ocupação
Ocupação é o número de blocos ativos na GPU. Embora não seja o objetivo final, permite ao planejador trocar um novo bloco para realizar cálculos enquanto outro espera por acessos de memória de alta latência da VRAM.
4. Utilização de Hardware
Para maximizar o desempenho, devemos alinhar nosso BLOCK_SIZE com as regras de agrupamento de memória da arquitetura da GPU, garantindo que threads consecutivas acessem endereços de memória consecutivos.